package factory

import (
	"fmt"
)

type PizzaStore interface {
	createPizza(t string) Pizza
	OrderPizza(t string) Pizza
}

type Pizza interface {
	prepare()
	bake()
	cut()
	box()
}

///////////////////////////////////////////
type NYStylePizzaStore struct {
}

func (f *NYStylePizzaStore) OrderPizza(t string) Pizza {
	var r Pizza
	r = f.createPizza(t)

	r.prepare()
	r.bake()
	r.cut()
	r.box()

	return r
}

func (f *NYStylePizzaStore) createPizza(t string) Pizza {
	switch t {
	case "cheese":
		return NewNYStyleCheesePizaa()
	case "veggie":
		return NewNYStyleVeggiePizza()
	case "clam":
		return NewNYStyleClamPizza()
	case "pepperoni":
		return NewNYStylePepperoniPizza()
	}

	return nil
}

type ChicagoStylePizzaStore struct {
}

func (f *ChicagoStylePizzaStore) OrderPizza(t string) Pizza {
	var r Pizza
	r = f.createPizza(t)

	r.prepare()
	r.bake()
	r.cut()
	r.box()

	return r
}

func (f *ChicagoStylePizzaStore) createPizza(t string) Pizza {
	switch t {
	case "cheese":
		return NewChicagoStyleCheesePizza()
	case "veggie":
		return NewChicagoStyleVeggiePizza()
	case "clam":
		return NewChicagoStyleClamPizza()
	case "pepperoni":
		return NewChicagoStylePepperoniPizza()
	}

	return nil
}

/////////////////////////////////////////////

type NYStyleCheesePizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewNYStyleCheesePizaa() *NYStyleCheesePizza {
	r := new(NYStyleCheesePizza)
	r.name = "NY Style Sauce and Cheese Pizza"
	r.dough = "Thin Crust Dough"
	r.sauce = "Marinara Sauce"

	r.toppings = append(r.toppings, "Grated Reggiano Chees")

	return r
}

func (f *NYStyleCheesePizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *NYStyleCheesePizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *NYStyleCheesePizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *NYStyleCheesePizza) box() {
	fmt.Println("Place pizza in official PizzaStore box")
}

type NYStyleVeggiePizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewNYStyleVeggiePizza() *NYStyleVeggiePizza {
	r := new(NYStyleVeggiePizza)
	r.name = "NY Style Veggie Pizza"
	r.dough = "Thin Crust Dough"
	r.sauce = "Marinara Sauce"

	r.toppings = append(r.toppings, "Grated Reggiano Cheese")
	r.toppings = append(r.toppings, "Garlic")
	r.toppings = append(r.toppings, "Onion")
	r.toppings = append(r.toppings, "Mushrooms")
	r.toppings = append(r.toppings, "Red Pepper")

	return r
}

func (f *NYStyleVeggiePizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *NYStyleVeggiePizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *NYStyleVeggiePizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *NYStyleVeggiePizza) box() {
	fmt.Println("Place pizza in official PizzaStore box")
}

type NYStyleClamPizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewNYStyleClamPizza() *NYStyleClamPizza {
	r := new(NYStyleClamPizza)
	r.name = "NY Style Clam Pizza"
	r.dough = "Thin Crust Dough"
	r.sauce = "Marinara Sauce"

	r.toppings = append(r.toppings, "Grated Reggiano Cheese")
	r.toppings = append(r.toppings, "Fresh Clams from Long Island Sound")

	return r
}

func (f *NYStyleClamPizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *NYStyleClamPizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *NYStyleClamPizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *NYStyleClamPizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}

type NYStylePepperoniPizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewNYStylePepperoniPizza() *NYStylePepperoniPizza {
	r := new(NYStylePepperoniPizza)
	r.name = "NY Style Pepperoni Pizza"
	r.dough = "Thin Crust Dough"
	r.sauce = "Marinara Sauce"

	r.toppings = append(r.toppings, "Grated Reggiano Cheese")
	r.toppings = append(r.toppings, "Sliced Pepperoni")
	r.toppings = append(r.toppings, "Garlic")
	r.toppings = append(r.toppings, "Onion")
	r.toppings = append(r.toppings, "Mushrooms")
	r.toppings = append(r.toppings, "Red Pepper")

	return r
}

func (f *NYStylePepperoniPizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *NYStylePepperoniPizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *NYStylePepperoniPizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *NYStylePepperoniPizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}

type ChicagoStyleCheesePizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewChicagoStyleCheesePizza() *ChicagoStyleCheesePizza {
	r := new(ChicagoStyleCheesePizza)
	r.name = "Chicago Style Deep Dish Cheese Pizza"
	r.dough = "Extra Thick Crust Dough"
	r.sauce = "Plum Tomato Sauce"

	r.toppings = append(r.toppings, "Shredded Mozzarella Cheese")

	return r
}

func (f *ChicagoStyleCheesePizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *ChicagoStyleCheesePizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *ChicagoStyleCheesePizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *ChicagoStyleCheesePizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}

type ChicagoStylePepperoniPizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewChicagoStylePepperoniPizza() *ChicagoStylePepperoniPizza {
	r := new(ChicagoStylePepperoniPizza)
	r.name = "Chicago Style Pepperoni Pizza"
	r.dough = "Extra Thick Crust Dough"
	r.sauce = "Plum Tomato Sauce"

	r.toppings = append(r.toppings, "Shredded Mozzarella Cheese")
	r.toppings = append(r.toppings, "Black Olives")
	r.toppings = append(r.toppings, "Spinach")
	r.toppings = append(r.toppings, "Eggplant")
	r.toppings = append(r.toppings, "Sliced Pepperoni")

	return r
}

func (f *ChicagoStylePepperoniPizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *ChicagoStylePepperoniPizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *ChicagoStylePepperoniPizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *ChicagoStylePepperoniPizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}

type ChicagoStyleClamPizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewChicagoStyleClamPizza() *ChicagoStyleClamPizza {
	r := new(ChicagoStyleClamPizza)
	r.name = "Chicago Style Clam Pizza"
	r.dough = "Extra Thick Crust Dough"
	r.sauce = "Plum Tomato Sauce"

	r.toppings = append(r.toppings, "Shredded Mozzarella Cheese")
	r.toppings = append(r.toppings, "Frozen Clams from Chesapeake Bay")

	return r
}

func (f *ChicagoStyleClamPizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *ChicagoStyleClamPizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *ChicagoStyleClamPizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *ChicagoStyleClamPizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}

type ChicagoStyleVeggiePizza struct {
	name     string
	dough    string
	sauce    string
	toppings []string
}

func NewChicagoStyleVeggiePizza() *ChicagoStyleVeggiePizza {
	r := new(ChicagoStyleVeggiePizza)
	r.name = "Chicago Deep Dish Veggie Pizza"
	r.dough = "Extra Thick Crust Dough"
	r.sauce = "Plum Tomato Sauce"

	r.toppings = append(r.toppings, "Shredded Mozzarella Cheese")
	r.toppings = append(r.toppings, "Black Olives")
	r.toppings = append(r.toppings, "Spinach")
	r.toppings = append(r.toppings, "Eggplant")

	return r
}

func (f *ChicagoStyleVeggiePizza) prepare() {
	fmt.Println("Preparing", f.name)
	fmt.Println("Tossing dough...")
	fmt.Println("Adding sauce...")
	fmt.Println("Adding  toppings:")
	for k, _ := range f.toppings {
		fmt.Println(" ", f.toppings[k])
	}
}

func (f *ChicagoStyleVeggiePizza) bake() {
	fmt.Println("Bake for 25 minutes at 350")
}

func (f *ChicagoStyleVeggiePizza) cut() {
	fmt.Println("Cutting the pizza into diagonal slices")
}

func (f *ChicagoStyleVeggiePizza) box() {
	fmt.Println("Place pizza in offcial PizzaStore box")
}
